import xmltodict

from core.services import get_vm_conn
from eve.models.libvirt_models import BaseModel
from eve.models.virtual_machine_network import LibvirtNetwork


class Node(BaseModel):
    value__: str = None


class Name(Node):
    value__: str

    def to_xml(self):
        return f'<name>{self.value__}</name>'


class Uuid(Node):
    pass

    def to_xml(self):
        return f'<uuid>{self.value__}</uuid>'


class Forward(Node):
    mode: str = 'nat'

    def to_xml(self):
        return f'<forward mode="{self.mode}" />'


class Bridge(Node):
    name: str = None
    stp: str = 'on'
    delay: int = 0

    def to_xml(self):
        if self.name is None: return ''
        return f'<bridge name="{self.name}" stp="{self.stp}" delay="{self.delay}" />'


class Mac(Node):
    address: str = None

    def to_xml(self):
        if self.address is None: return ''
        return f'<mac address="{self.address}" />'


class IpDhcpRange(BaseModel):
    start: str
    end: str


class Ip(Node):
    address: str
    netmask: str = '255.255.255.0'

    def to_xml(self):
        return f'<ip address="{self.address}" netmask="{self.netmask}" />'


class Network(BaseModel):
    name: str
    uuid: str = None
    forward: Forward
    bridge: Bridge
    mac: Mac = None
    ip: Ip

    @classmethod
    def all(cls):
        client = get_vm_conn()
        conn = next(client)

        virNetworks = conn.listAllNetworks()
        data = []
        for i, _ in enumerate(virNetworks):
            network = cls.from_xml(_.XMLDesc())
            data.append(network.to_model_dict())
            # d = {
            #     "name": "my_network_0",
            #     "uuid": "bb82c9f1-1f08-4364-93af-3ba838715d5a",
            #     "forward_mode": "nat",
            #     "bridge_name": "virbr1",
            #     "bridge_stp": "on",
            #     "bridge_delay": "0",
            #     "mac_address": "52:54:00:14:09:ab",
            #     "ip_address": "192.168.142.1",
            #     "ip_netmask": "255.255.255.0",
            #     "ip_dhcp_range_start": "192.168.142.2",
            #     "ip_dhcp_range_end": "192.168.142.254",
            #     "id": 1
            # }
            # d['network']['id'] = i

        return data

    def to_xml(self):
        s = ''
        s += '<network>'
        s += f'<name>{self.name}</name>'
        if self.uuid: s += f'<uuid>{self.uuid}</uuid>'
        s += self.forward.to_xml()
        s += self.bridge.to_xml()
        s += self.mac.to_xml()
        s += self.ip.to_xml()
        s += '</network>'

        return s

    @staticmethod
    def build_network_xml(name: str, ip_address, ip_netmask='255.255.255.0', forward_mode: str = 'nat',
                          bridge_name=None, bridge_delay=0, mac_address=None):
        return Network(
            name=name,
            # uuid=None,
            forward=Forward(mode=forward_mode),
            bridge=Bridge(name=bridge_name, delay=bridge_delay),
            mac=Mac(address=mac_address),
            ip=Ip(address=ip_address, netmask=ip_netmask)
        ).to_xml()

    @staticmethod
    def from_xml(xmlDesc):
        d = xmltodict.parse(xmlDesc)['network']
        return Network(
            name=d['name'],
            uuid=d['uuid'],
            forward=Forward(mode=d['forward']['@mode']),
            bridge=Bridge(name=d['bridge']['@name'], stp=d['bridge']['@stp'], delay=d['bridge']['@delay']),
            mac=Mac(address=d['mac']['@address']),
            ip=Ip(address=d['ip']['@address'], netmask=d['ip']['@netmask'])
        )

    def to_model_dict(self):
        return {
            "name": self.name,
            "uuid": self.uuid,
            "forward_mode_type": LibvirtNetwork.FORWARD_MODE_TYPE[self.forward.mode].value,
            "bridge_name": self.bridge.name,
            "bridge_stp": self.bridge.stp,
            "bridge_delay": self.bridge.delay,
            "mac_address": self.mac.address,
            "ip_address": self.ip.address,
            "ip_netmask": self.ip.netmask,
            # "ip_dhcp_range_start": self.ip,
            # "ip_dhcp_range_end": "192.168.142.254",
        }
